package com.xzzz.irda.guardcat.core.metric.jvm;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import com.sun.tools.attach.AttachNotSupportedException;
import com.sun.tools.attach.VirtualMachine;
import com.xzzz.common.base.util.ConvertUtil;
import sun.tools.attach.HotSpotVirtualMachine;

import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.charset.StandardCharsets;
import java.util.Date;

/**
 * 虚拟机信息
 *
 * @author xzzz
 * @since 1.0.0
 */
public class JvmInfo implements Serializable {
    private static final long serialVersionUID = 1L;

    /**
     * Java 虚拟机进程名称
     */
    private String processName;

    /**
     * 进程 Id
     */
    private int processId;

    /**
     * 虚拟机名称
     */
    private String vmName;

    /**
     * 版本号
     * java.version
     */
    private String javaVersion;

    /**
     * 供应商
     * java.vm.vendor
     */
    private String vmVendor;

    /**
     * java home 路径
     * java.home
     */
    private String javaHome;

    /**
     * 库路径
     * java.library.path
     */
    private String libraryPath;

    /**
     * 引导类路径
     */
    private String bootClassPath;

    /**
     * 扩展路径
     *      java.ext.dirs
     */
    // private String extDirs;

    /**
     * 类路径
     * java.class.path
     */
    private String classPath;

    /**
     * 类格式版本号
     * java.class.version
     */
    private String classVersion;

    /**
     * 临时文件路径
     * java.io.tmpdir
     */
    private String ioTempDir;

    /**
     * 虚拟机输入参数
     */
    private String inputArguments;

    /**
     * 启动时间
     */
    private Date startTime;

    /**
     * 运行时间
     */
    private long uptime;

    /**
     * 构造器私有化
     */
    private JvmInfo() {
    }

    /**
     * 获取 JVM 信息
     *
     * @return JvmInfo
     */
    public static JvmInfo getJvmInfo() {
        JvmInfo jvmInfo = new JvmInfo();

        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        jvmInfo.processName = runtimeMxBean.getName();
        jvmInfo.processId = Integer.parseInt(jvmInfo.processName.split("@")[0]);
        jvmInfo.vmName = runtimeMxBean.getVmName();
        jvmInfo.javaVersion = System.getProperty("java.version");
        jvmInfo.vmVendor = runtimeMxBean.getVmVendor();
        jvmInfo.javaHome = System.getProperty("java.home");
        jvmInfo.libraryPath = runtimeMxBean.getLibraryPath();
        jvmInfo.bootClassPath = runtimeMxBean.getBootClassPath();
        // jvmInfo.extDirs = System.getProperty("java.ext.dirs");
        jvmInfo.classPath = runtimeMxBean.getClassPath();
        jvmInfo.classVersion = System.getProperty("java.class.version");
        jvmInfo.ioTempDir = System.getProperty("java.io.tmpdir");
        jvmInfo.inputArguments = ConvertUtil.collectionToString(" ", runtimeMxBean.getInputArguments());
        jvmInfo.startTime = new Date(runtimeMxBean.getStartTime());
        jvmInfo.uptime = runtimeMxBean.getUptime();

        return jvmInfo;
    }

    /**
     * 获取所有线程堆栈快照信息
     *
     * @param pid 进程 ID;
     * @return String 统计信息
     */
    public static String getFullThreadDumpMsg(String pid) {
        InputStream is = null;
        if (StrUtil.isEmpty(pid)) {
            pid = getJvmProcessId();
        }
        try {
            HotSpotVirtualMachine machine = (HotSpotVirtualMachine) VirtualMachine.attach(pid);
            is = machine.remoteDataDump("");
            return IoUtil.read(is, StandardCharsets.UTF_8.name());
        } catch (AttachNotSupportedException | IOException e) {
            throw new RuntimeException("获取线程堆栈信息时异常");
        } finally {
            IoUtil.close(is);
        }
    }

    /**
     * 获取堆内存中对象统计信息
     *
     * @param pid 进程 ID;
     * @return String 统计信息
     */
    public static String getHeapMemoryObjectStatistics(String pid) {
        InputStream is = null;
        if (StrUtil.isEmpty(pid)) {
            pid = getJvmProcessId();
        }
        try {
            HotSpotVirtualMachine machine = (HotSpotVirtualMachine) VirtualMachine.attach(pid);
            is = machine.heapHisto("");
            return IoUtil.read(is, StandardCharsets.UTF_8.name());
        } catch (AttachNotSupportedException | IOException e) {
            throw new RuntimeException("获取堆内存对象统计时异常");
        } finally {
            IoUtil.close(is);
        }
    }

    /**
     * 通过 Jcmd 执行命令
     *
     * @param command 命令
     * @return String 执行结果
     */
    public static String executeCommandByJcmd(String command) {
        // RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        InputStream is = null;
        try {
            HotSpotVirtualMachine machine = (HotSpotVirtualMachine) VirtualMachine.attach(getJvmProcessId());
            is = machine.executeJCmd(command);
            return IoUtil.read(is, StandardCharsets.UTF_8.name());
        } catch (AttachNotSupportedException | IOException e) {
            throw new RuntimeException("通过 Jcmd 执行命令时异常");
        } finally {
            IoUtil.close(is);
        }
    }

    /**
     * 获取 JVM 进程 Id
     *
     * @return String 进程 Id
     */
    public static String getJvmProcessId() {
        RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean();
        return runtimeMxBean.getName().split("@")[0];
    }

    public String getProcessName() {
        return processName;
    }

    public int getProcessId() {
        return processId;
    }

    public String getVmName() {
        return vmName;
    }

    public String getJavaVersion() {
        return javaVersion;
    }

    public String getVmVendor() {
        return vmVendor;
    }

    public String getJavaHome() {
        return javaHome;
    }

    public String getLibraryPath() {
        return libraryPath;
    }

    public String getBootClassPath() {
        return bootClassPath;
    }

    /*public String getExtDirs() {
        return extDirs;
    }*/

    public String getClassPath() {
        return classPath;
    }

    public String getClassVersion() {
        return classVersion;
    }

    public String getIoTempDir() {
        return ioTempDir;
    }

    public String getInputArguments() {
        return inputArguments;
    }

    public Date getStartTime() {
        return startTime;
    }

    public long getUptime() {
        return uptime;
    }

    @Override
    public String toString() {
        return "虚拟机信息{" +
                "进程名称='" + processName + '\'' +
                ", 进程Id=" + processId +
                ", 虚拟机名称='" + vmName + '\'' +
                ", java版本号='" + javaVersion + '\'' +
                ", 虚拟机供应商='" + vmVendor + '\'' +
                ", javaHome='" + javaHome + '\'' +
                ", 库路径='" + libraryPath + '\'' +
                ", 引导类路径='" + bootClassPath + '\'' +
                // ", 扩展路径='" + extDirs + '\'' +
                ", 类路径='" + classPath + '\'' +
                ", 类格式版本号='" + classVersion + '\'' +
                ", 临时文件路径='" + ioTempDir + '\'' +
                ", 虚拟机输入参数='" + inputArguments + '\'' +
                ", 虚拟机启动时间=" + startTime +
                ", 虚拟机运行时间='" + uptime + "毫秒'" +
                '}';
    }

    /*
    public static void main(String[] args) {
        System.out.println(getHeapMemoryObjectStatistics(getJvmInfo().processId + ""));
        System.out.println();
        System.out.println(getFullThreadDumpMsg(""));
    }
    */
}
